/*
 * fork_process.c
 *	 对 fork() 的简单包装。此函数不处理
 *	 EXEC_BACKEND 情况；可以扩展以处理，但会
 *	 显著增加复杂性。
 *
 * Copyright (c) 1996-2022, PostgreSQL Global Development Group
 *
 * IDENTIFICATION
 *	  src/backend/postmaster/fork_process.c
 */
#include "postgres.h"

#include <fcntl.h>
#include <time.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <unistd.h>

#include "miscadmin.h"
#include "postmaster/fork_process.h"

#ifndef WIN32
/* 
 * fork() 的包装器。返回值与 fork() 的返回值相同：
 * -1 如果 fork 失败，0 在子进程中，父进程中为子进程的 PID。
 */
pid_t fork_process(void)
{
	pid_t		fc_result;
	const char *fc_oomfilename;

#ifdef LINUX_PROFILE
	struct itimerval fc_prof_itimer;
#endif

	
/*
	 * 在 fork 之前刷新标准 I/O 通道，以避免重复输出的问题。
	 * 理想情况下我们在这里使用 fflush(NULL)，但是仍然有一些非 ANSI
	 * 的标准 I/O 库（如 SunOS 4.1.x）如果这样做会崩溃。
	 * 目前，stdout 和 stderr 是主进程使用的唯一标准 I/O 输出通道，
	 * 所以刷新它们应该足够了。
	 */
	fflush(stdout);
	fflush(stderr);

#ifdef LINUX_PROFILE

	/*
	 * Linux 的 fork() 在子进程中重置剖析定时器。如果我们要对
	 * 子进程进行剖析，则需要保存和恢复定时器设置。
	 * 不过，如果不进行剖析，这样做就是浪费时间，所以
	 * 只在特定的 -DLINUX_PROFILE 开关命令下执行。
	 */
	getitimer(ITIMER_PROF, &fc_prof_itimer);
#endif

	fc_result = fork();
	if (fc_result == 0)
	{
		/* fork 成功，在子进程中 */
		MyProcPid = getpid();
#ifdef LINUX_PROFILE
		setitimer(ITIMER_PROF, &fc_prof_itimer, NULL);
#endif

		/*
		 * 默认情况下，Linux 在内存不足的情况下倾向于终止主进程，
		 * 因为它将主进程归咎于子进程大小的总和 *包括共享内存*。
		 * （这真是令人难以置信的愚蠢，但内核黑客似乎对改进这点不感兴趣。）
		 * 因此，通常通过将主进程的 OOM 分数调整为负值来保护主进程是个好主意
		 * （这必须在由 root 拥有的启动脚本中完成）。
		 * 由于该调整会被子进程继承，这通常意味着所有主进程的子进程在 OOM
		 * 杀死时都受到同等保护，但这并不是个好主意。
		 * 所以我们提供了这段代码，允许子进程再次改变它们的 OOM 分数调整。
		 * 要写入的文件名和要写入的值由环境变量控制，这些变量可以由
		 * 进行原始调整的相同启动脚本设置。
		 */
		fc_oomfilename = getenv("PG_OOM_ADJUST_FILE");

		if (fc_oomfilename != NULL)
		{
			/*
			 * 使用 open() 而不是 stdio，以确保我们控制打开标志。一些
			 * Linux 安全环境拒绝使用除 O_WRONLY 以外的任何操作。
			 */
			int			fc_fd = open(fc_oomfilename, O_WRONLY, 0);

			/* 我们忽略所有错误 */
			if (fc_fd >= 0)
			{
				const char *fc_oomvalue = getenv("PG_OOM_ADJUST_VALUE");
				int			fc_rc;

				if (fc_oomvalue == NULL)	/* 提供一个有用的默认值 */
					fc_oomvalue = "0";

				fc_rc = write(fc_fd, fc_oomvalue, strlen(fc_oomvalue));
				(void) fc_rc;
				close(fc_fd);
			}
		}

		/* 在 Fork 后进行随机数生成的初始化 */
		pg_strong_random_init();
	}

	return fc_result;
}

#endif							/* ! WIN32 */
